#import
import tensorflow as tf
from tensorflow.keras import layers, models
import matplotlib.pyplot as plt
import numpy as np

# load dataset
(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()

# 数据预处理，归一化到[0,1]范围
train_images = train_images.reshape((60000, 28, 28, 1)).astype('float32') / 255
test_images = test_images.reshape((10000, 28, 28, 1)).astype('float32') / 255

# 构建卷积神经网络模型
model = models.Sequential([
    # 第1个卷积层
    layers.Conv2D(32, (3, 3), activation = 'relu', input_shape = (28, 28, 1)),
    layers.MaxPooling2D((2, 2)),

    # 第2个卷积层
    layers.Conv2D(64, (3, 3), activation = 'relu'),
    layers.MaxPooling2D((2, 2)),
    
    # 全连接分类器
    layers.Flatten(),
    layers.Dense(64, activation = 'relu'),
    layers.Dense(10, activation = 'softmax') #输出层,10
])

# 编译
model.compile(optimizer = 'adam',
              loss = 'sparse_categorical_crossentropy',
              metrics = ['accuracy']
)

# train
history = model.fit(
    train_images,
    train_labels,
    epochs = 5,
    batch_size = 64,
    validation_split = 0.2
)

test_loss, test_acc = model.evaluate(test_images, test_labels)
print(f'\n测试准确率：{test_acc:.4f}')

# 可视化训练过程
plt.plot(history.history['accuracy'], label = 'accuracy')
plt.plot(history.history['val_accuracy'], label = 'val_accuracy')
plt.xlabel('Epoch')
plt.ylabel('accuracy')
plt.legend()
plt.show()

# 进行单个预测
def predict_image(img):
    """预测单个实例"""
    img = img.reshape((1, 28, 28, 1))
    prediction = model.predict(img)
    return prediction.argmax()

# 随机选择一个图像预测
index = np.random.randint(0, len(test_images))
sample_image = test_images[index]
true_label = test_labels[index]

predict_lable = predict_image(sample_image)
print(f"\n True label: {true_label}, Predict: {predict_lable}")

# 可视化样本图像
plt.imshow(sample_image.reshape(28, 28, 1), cmap = 'gray')
plt.title(f"True: {true_label}, Predict:{predict_lable}")
plt.axis('off')
plt.show()